package nl.scalasim
package actors

import nl.scalasim.actors.traits._
import nl.scalasim.actors.citizenactivities._

/**
 * Citizens live in our simulated cities; they live at Housing locations,
 * and work at Workplace locations. When they're off duty, they travel
 * around as dictated by the needs of their Housing.  
 *
 * @author Yigal Duppen
 * @since Oct 7, 2010
 */
class Citizen(val addressBook: AddressBook, override val descriptor: ActorDescriptor, val ticksAtHome: Int, val ticksAtWork: Int, val carryingCapacity: Int)
        extends SimulationActor(descriptor)
                with StoppableActor
                with Logging
{

  val atHome = new AtHomeActivity(this)
  val commuting = new CommutingActivity(this)
  var atWork: Activity = _

  private[actors] var house: SimulationActor = _
  private[actors] var workplace: Option[SimulationActor] = None
  private[actors] var carrying: Option[(Goods, Int)] = None 

  private var _currentActivity: Activity = new IdleActivity(this)
  def currentActivity: Activity = _currentActivity
  
  def currentActivity_=(a: Activity) = {
    _currentActivity = a
    _currentActivity.activate
  }


  override def handleGetState = {
    case GetState => {
      val stored: Map[Goods, Amount] = carrying match {
        case None => Map()
        case Some(x) => Map(x._1 -> Amount(x._2, carryingCapacity))
      }
      val related = workplace match {
        case None => Set(house)
        case Some(x) => Set(house, x)
      }

      reply(ActorState(descriptor = descriptor,
        stored = stored,
        maxCapacity = carryingCapacity,
        workers = Amount(0, 0),
        residents = Amount(0, 0),
        related = related))
    }
  }

  def handleAct: PartialFunction[Any, Unit] = {
    case Arrived(a) => {
      currentActivity.handleArrived(a)
    }

    case Found(Some(a)) => {
      currentActivity.handleFound(a)
    }
    case Found(None) => {
      log.warning("No actor found")
    }

    case Act => {
      currentActivity.handleAct(sender)
    }
  }
  callbacks :+= handleAct


  def handleLiveAt: PartialFunction[Any, Unit] = {
    case LiveAt(_, h) => {
      house = h
      reply(Ack)
    }
  }
  callbacks :+= handleLiveAt


  def handleWorkAt: PartialFunction[Any, Unit] = {
    case WorkAt(_, w) => {
      workplace = Some(w)
      // todo: use capabilities
      if (w.isInstanceOf[HarvestingActor]) {
        atWork = new AtWorkAtHarvesterActivity(this)
      }
      else if (w.isInstanceOf[StorageActor]) {
        atWork = new AtWorkAtStorageActivity(this)
      }
      else {
        error("Unknown workplace type: " + w)
      }
      reply(Ack)
    }
  }
  callbacks :+= handleWorkAt


}

